home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / nntpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-16  |  55.0 KB  |  2,654 lines

  1. /*
  2.  *
  3.  * NNTP Server/Client - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  *
  11.  * ported to NOS by PE1NMB - 920120
  12.  *
  13.  * Mods by PA0GRI, WG7J and KO4KS
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <time.h>
  18. #include <stdarg.h>
  19. #include <ctype.h>
  20. #include <setjmp.h>
  21. #include <dos.h>
  22. #include <dir.h>
  23. #ifdef UNIX
  24. #include <sys/types.h>
  25. #endif
  26. #include <sys/stat.h>
  27. #include <io.h>
  28. #include <string.h>
  29. #include "global.h"
  30. #include "config.h"
  31. #ifdef NNTPS
  32. #include "mbuf.h"
  33. #include "cmdparse.h"
  34. #include "socket.h"
  35. #include "iface.h"
  36. #include "proc.h"
  37. #include "smtp.h"
  38. #include "commands.h"
  39. #include "dirutil.h"
  40. #include "ftp.h"
  41. #include "netuser.h"
  42. #include "nntp.h"
  43. #include "session.h"
  44. #include "files.h"
  45. #include "smtp.h"
  46. #include "bm.h"
  47. #ifdef LESS_WHINING
  48. #include "pc.h"
  49. #include "usock.h"
  50. #include "nr4.h"
  51. #include "netrom.h"
  52. #include "udp.h"
  53. #include "tcp.h"
  54. #include "ip.h"
  55. #endif
  56.  
  57. int setintrc __ARGS((int16 *var,char *label,int argc, char *argv[],int minval,int16 maxval));
  58. extern int subcmd __ARGS((struct cmds tab[],int argc,char *argv[],void *p));
  59. FILE *open_file __ARGS((char *name,char *mode,int s,int t));
  60. FILE *temp_file __ARGS((int s,int t));     /*                            NMB */
  61.  
  62. /***************************************************************************/
  63.  
  64.  
  65. #undef CONTROL                /* reverse NNTP function (not implemented yet) */
  66. #define    LINE    80
  67.  
  68. static int Snntp = -1;      /* prototype socket for service */
  69. static int16 Nntpquiet = 0;
  70. int Filecheck = 0;            /* flag if file system has been checked */
  71.  
  72. struct post *Post = NULLPOST;
  73. struct Servers *Nntpserver = NULLSERVER;
  74.  
  75. static char *Host    = NULLCHAR;
  76. static char NEol[]     = ".\n";
  77.  
  78. /*############################ NNTP COMMANDS #################################*/
  79.  
  80. /* Command table */
  81. static char *commands[] = {
  82.     "quit",
  83. #define QUIT_CMD    0
  84.     "help",
  85. #define HELP_CMD    1
  86.     "list",
  87. #define LIST_CMD    2
  88.     "group",
  89. #define GROUP_CMD    3
  90.     "debug",
  91. #define DEBUG_CMD    4
  92.     "article",
  93. #define ARTICLE_CMD    5
  94.     "next",
  95. #define NEXT_CMD    6
  96.     "xinfo",
  97. #define XINFO_CMD    7
  98.     "ihave",
  99. #define IHAVE_CMD    8
  100.     "newnews",
  101. #define NEWNEWS_CMD    9
  102.     "head",
  103. #define HEAD_CMD    10
  104.     "body",
  105. #define BODY_CMD    11
  106.     "stat",
  107. #define STAT_CMD    12
  108.     "last",
  109. #define LAST_CMD    13
  110.     "slave",
  111. #define SLAVE_CMD    14
  112.     NULLCHAR
  113. };
  114.  
  115. static char artmsg[]     = " Article retrieved - ";
  116.  
  117. static char info[]    = "100 %s Info:\n";
  118. static char xinfo[]    = "100 No info available\n";
  119. static char debug[]    = "100 DEBUG %s\n";
  120.  
  121. static char nnversion[]    = "20%s %s NNTP version %s ready at %s\n";
  122. static char slave[]        = "202 SLAVE %s\n";
  123. static char closing[]    = "203 Closing\n";
  124. static char listarticle[]= "211 %u %u %u%s\n";
  125. static char retrieve[]     = "220 %u%s%shead and body follow\n";
  126. static char head[]    = "221 %u%s%sHead\n";
  127. static char body[]    = "222 %u%s%sBody\n";
  128. static char statistics[]= "223 %u%s%sStatistics\n";
  129. static char sepcmd[]    = "223 %u%s%srequest text separately\n";
  130. static char newnews_t[]    = "230 New news by message id follows\n";
  131. static char transok[]    = "235 Thanks\n";
  132.  
  133. static char sendart[]    = "335 Send article, end with .\n";
  134.  
  135. static char nogroup[]    = "411 No such newsgroup\n";
  136. static char noselect[]    = "412 No newsgroup selected\n";
  137. static char nonext[]    = "421 No next article\n";
  138. static char noprev[]    = "422 No previous article\n";
  139. static char noart[]    = "430 No such article\n";
  140. static char notwanted[]    = "435 Article not wanted - do not send it\n";
  141. static char transnotok[]= "437 Article rejected - header garbled - do not try again\n";
  142.  
  143. static char badsyntax[]    = "501 Syntax error\n";
  144. static char error[]    = "503 Command not performed\n";
  145. static char nospace[]    = "503 Not enough disk space left\n";
  146. static char lowmem[]    = "503 System overloaded\n";
  147. static char fatal[]    = "503 Fatal error FILE %s\n";
  148.  
  149. static char quitcmd[]    = "QUIT\n";
  150. static char help[]    = "NNTP Server 1992,\n\n100 ARTICLE  BODY  GROUP   HEAD  HELP IHAVE\n100 LAST     LIST  NEWNEWS NEXT  QUIT STAT\n";
  151.  
  152. #ifdef MSDOS
  153. static void near
  154. #else
  155. static void
  156. #endif
  157. rip2(s)
  158. register char *s;
  159. {
  160.     register char *cp;
  161.  
  162. #ifndef TNOS_68K
  163.     if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
  164. #else
  165.     if((cp = strpbrk(s,"\r\l")) != NULLCHAR)
  166. #endif
  167.         *cp = '\0';
  168. }
  169.  
  170. /* main directory-creating routine
  171.  * handles special chars in pathname - especially for MSDOS
  172.  * returncode: -1 error; 0 success
  173.  */
  174. #ifdef MSDOS
  175. static int near
  176. #else
  177. static int
  178. #endif
  179. make_dir(path,s)
  180. char *path;
  181. int s;
  182. {
  183.     register char *cp;
  184.  
  185.     if(path == NULLCHAR)
  186.         return -1;
  187. #ifdef MSDOS
  188.     while((cp = strchr(path,'\\')) != NULLCHAR)
  189.         *cp = '/';
  190. #endif
  191. #ifndef TNOS_68K
  192.     if (access(path,0)) {
  193. #else
  194.     if (access(path,0x80)) {
  195. #endif
  196.         if (mkdir(path)) {
  197.             tprintf("Can't create %s: %s\n",path,sys_errlist[errno]);
  198.             if(s)
  199.                 usprintf(s,fatal,path);
  200.             return -1;
  201.         }
  202.     }
  203.     return 0;
  204. }
  205.  
  206. /* main message-opening routine
  207.  * returncode: NULLFILE if error; filepointer success */
  208. static FILE *
  209. open_message(mp,f)
  210. struct nntpsv *mp;
  211. FILE *f;
  212. {
  213.     char line[LineLen];
  214.  
  215.     /* mp already checked */
  216.  
  217.     if(f != NULLFILE)
  218.         fclose(f);
  219.  
  220.     sprintf(line,"%s/%u",mp->path,mp->pointer);
  221.  
  222.     if ((f = open_file(line,READ_TEXT,0,0)) == NULLFILE)
  223.         usputs(mp->s,noart);
  224.     return f;
  225. }
  226.  
  227. /* file-receiving routine
  228.  * returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
  229. static int
  230. recv_file(fp,s)
  231. FILE *fp;
  232. int s;
  233. {
  234.     char line[LineLen];
  235.     int check = 0;
  236.  
  237.     for (;;) {
  238.         if (recvline(s,line,LineLen) == -1)
  239.             return -1;
  240.         rip2(line);
  241.         if (strcmp(line,".") == 0) {
  242.             return 0;
  243.         }
  244.         if(!check) {                  /* only enabled on first line! */
  245.             check = 1;
  246.             if (*line == '\0')         /* check for blank line */
  247.                 return 1;
  248.         }
  249.         fprintf(fp,"%s\n",line);
  250.     }
  251. }
  252.  
  253. /* checks incoming article-id against existing articles
  254.  * returncode: -1 if error; 1 if article exists; 0 no article found */
  255. static int
  256. check_article(id)
  257. char *id;
  258. {
  259.     char *p, line[LineLen];
  260.     FILE *f;
  261.  
  262.     if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
  263.       || (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  264.         return -1;
  265.  
  266.     for(;;) {
  267.         if (fgets(line,LineLen,f) == NULL) {
  268.             fclose(f);
  269.             return 0;
  270.         }
  271.         if (strstr(line,p) != NULL) {
  272.             fclose(f);
  273.             return 1;
  274.         }
  275.     }
  276. }
  277.  
  278. /* checks for not valid chars in a line
  279.  * returncode: 0 if valid; 1 if invalid */
  280. static int
  281. check_blank(bp)
  282. char *bp;
  283. {
  284.     if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
  285.         return 1;
  286.     return 0;
  287. }
  288.  
  289. /* main file-checking routine
  290.  * returncode: -1 if error; 0 success */
  291. static int
  292. check_file(path)
  293. char *path;
  294. {
  295.     if(path == NULLCHAR)
  296.         return -1;
  297.     if(access(path,0))
  298.         return close(creat(path,S_IWRITE));
  299.     return 0;
  300. }
  301.  
  302. /* checks if two spaces exists in given string
  303.  * returncode: -1 if error; 1 success */
  304. static int
  305. check_one(str)
  306. register char *str;
  307. {
  308.     register char *cp;
  309.  
  310.     if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
  311.         return -1;
  312.     cp++;
  313.  
  314.     if (strchr(cp,' ') == NULLCHAR)
  315.         return -1;
  316.  
  317.     return 1;
  318. }
  319.  
  320. /* checks the file-system used for NNTP
  321.  * returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
  322. static int
  323. check_system()
  324. {
  325.     FILE *f;
  326.     char line[LineLen];
  327.     int error = 0;
  328.  
  329.     if (Post == NULLPOST)
  330.         donnprofile(10,NULL,NULL);
  331.  
  332.     if(Filecheck)
  333.         return 0;
  334.  
  335.     error  = make_dir(Forward,0);
  336.     error |= check_file(Pointer);
  337.     error |= check_file(History);
  338.     error |= check_file(Active);
  339.     error |= check_file(Poll);
  340.  
  341.     if(error)
  342.         goto quit;
  343.  
  344.     sprintf(line,"%s/fwd.seq",Newsdir);
  345.     if (access(line,0)) {
  346.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  347.             goto quit;
  348.         }
  349.         fputs("1\n",f);
  350.         fclose(f);
  351.     }
  352.     sprintf(line,"%s/sequence.seq",Mailqdir);
  353.     if (access(line,0)) {
  354.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  355.             goto quit;
  356.         }
  357.         fputs("1\n",f);
  358.         fclose(f);
  359.     }
  360.     Filecheck = 1;
  361.     return 0;
  362.  
  363. quit:
  364.     Filecheck = 0;
  365.     tputs("Error in NNTP file system\n");
  366.     return -1;
  367. }
  368.  
  369. /* handles the response code of an incoming msg
  370.  * returncode: -1 error; 0 no code; value of response code on success */
  371. static int
  372. getreply(cb)
  373. struct nntpsv *cb;
  374. {
  375.     int response;
  376.  
  377.     while(recvline(cb->s,cb->buf,LineLen) != -1) {
  378.         /* skip informative messages and blank lines */
  379.         if(cb->buf[0] == '\0' || cb->buf[0] == '1')
  380.             continue;
  381.         sscanf(cb->buf,"%d",&response);
  382.         return (response < 500) ? response : -1;
  383.     }
  384.     return -1;
  385. }
  386.  
  387. /* returncode: -1 error; 1 success; 0 no entry */
  388. static int
  389. get_path(group,mp)
  390. char *group;
  391. struct nntpsv *mp;
  392. {
  393.     FILE *f;
  394.     char line[LineLen], *cp;
  395.  
  396.     if(group == NULLCHAR || mp == NULLNNTPSV
  397.       || (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
  398.         return -1;
  399.  
  400.     group++;
  401.  
  402.     for (;;) {
  403.         if (fgets(line,LineLen,f) == NULL)
  404.             break;
  405.         if (strcspn(line," ") != strlen(group))
  406.             continue;
  407.         if (strnicmp(group,line,strlen(group)) == 0) {
  408.             cp = (strchr(line,' ')) + 1;
  409.             if (mp->path != NULLCHAR)
  410.                 free(mp->path);
  411.             mp->path = strdup(cp);
  412.             rip2(mp->path);
  413.             fclose(f);
  414.             return 1;
  415.         }
  416.     }
  417.     fclose(f);
  418.     return 0;
  419. }
  420.  
  421. /* checkes if path to given article exists
  422.  * returncode: -1 error; 1 success; 0 no path */
  423. static int
  424. get_path2(art)
  425. struct article *art;
  426. {
  427.     FILE *f;
  428.     char line[LineLen], *p;
  429.  
  430.     if(art->group == NULLCHAR
  431.       || (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  432.         return -1;
  433.  
  434.     p = art->group;
  435.     art->path = NULLCHAR;
  436.  
  437.     for (;;) {
  438.         if (fgets(line,LineLen,f) == NULL)
  439.             break;
  440.         if (strcspn(line," ") != strlen(p))
  441.             continue;
  442.         if (strnicmp(p,line,strlen(p)) == 0) {
  443.             p = (strchr(line,' ')) + 1;
  444.             if(art->path != NULLCHAR)
  445.                 free(art->path);
  446.             art->path = strdup(p);
  447.             rip2(art->path);
  448.             fclose(f);
  449.             return 1;
  450.         }
  451.     }
  452.     fclose(f);
  453.     return 0;
  454. }
  455.  
  456. /* returncode: -1 if error; 1 success; 0 no pointer */
  457. static int
  458. get_pointer(group,mp)
  459. char *group;
  460. struct nntpsv *mp;
  461. {
  462.     FILE *f;
  463.     char line[LineLen], *p;
  464.  
  465.     if(group == NULLCHAR || mp == NULLNNTPSV
  466.       || (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
  467.         return -1;
  468.  
  469.     group++;
  470.  
  471.     for (;;) {
  472.         if (fgets(line,LineLen,f) == NULL)
  473.             break;
  474.         if (strcspn(line," ") != strlen(group))
  475.             continue;
  476.         if (strnicmp(group,line,strlen(group))==0) {
  477.             p = strchr(line,' ');
  478.             mp->last = (unsigned)atoi(p);
  479.             p++;
  480.             mp->first = (unsigned)atoi(strchr(p,' '));
  481.             mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
  482.             fclose(f);
  483.             return 1;
  484.         }
  485.     }
  486.     fclose(f);
  487.     return 0;
  488. }
  489.  
  490. /* creating path to a new newsgroup
  491.  * handling of "." and "\" in pathnames especially MSDOS */
  492. /* returncode: -1 error; 0 success */
  493. static int
  494. make_path(group)
  495. char *group;
  496. {
  497.     FILE *f;
  498.     char cp[LineLen], cp1[LineLen], *cp2;
  499.     int got_it;
  500.  
  501.     if (group == NULLCHAR
  502.       || (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
  503.         return -1;
  504.  
  505.     got_it = 0;
  506.     strcpy(cp1,group);
  507.  
  508.     for(;;) {
  509.         if((cp2 = strchr(cp1,'.')) != NULLCHAR)
  510.             *cp2 = '\0';
  511.         else
  512.             got_it = 1;
  513.  
  514.         sprintf(cp,"%s/%s",Newsdir,cp1);
  515.  
  516.         if(make_dir(cp,0)) {
  517.             fclose(f);
  518.             return -1;
  519.         }
  520.         if(got_it) {
  521.             fprintf(f,"%s %s\n",group,cp);
  522.             fclose(f);
  523.             return 0;
  524.         }
  525.         *cp2 = '/';
  526.     }
  527. }
  528.  
  529. static int
  530. update_list(a)
  531. struct nntpsv *a;
  532. {
  533.     FILE *f, *t;
  534.     char *p, *p1, l2[LineLen];
  535.  
  536.     if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
  537.         return -1;
  538.  
  539.     if ((t = temp_file(0,1)) == NULLFILE) {
  540.         fclose(f);
  541.         return -1;
  542.     }
  543.     p1 = a->ap->group;
  544.     a->ap->number = 0;
  545.     for (;;) {
  546.         if (fgets(a->buf,LineLen,f) == NULL)
  547.             break;
  548.         a->ap->tmpu = strcspn(a->buf," ");
  549.         strncpy(l2,a->buf,a->ap->tmpu);
  550.         l2[a->ap->tmpu] = '\0';
  551.         if (strcmp(p1,l2) == 0) {
  552.             p = strchr(a->buf,' ') + 1;
  553.             a->ap->number = (unsigned)atoi(p);
  554.             (a->ap->number)++;
  555.             p = strchr(p,' ');
  556.             fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
  557.         } else
  558.             fputs(a->buf,t);
  559.     }
  560.     fclose(f);
  561.     rewind(t);
  562.     if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
  563.         fclose(t);
  564.         return -1;
  565.     }
  566.     for(;;) {
  567.         if (fgets(a->buf,LineLen,t) == NULL)
  568.             break;
  569.         fputs(a->buf,f);
  570.     }
  571.     fclose(t);
  572.     if (a->ap->number == 0) {
  573.         make_path(a->ap->group);
  574.         a->ap->number = 1;
  575.         fprintf(f,"%s 00001 00001 y\n",a->ap->group);
  576.     }
  577.     fclose(f);
  578.     return (a->ap->number);
  579. }
  580.  
  581. /* returncode: -1 error; 0 success */
  582. static int
  583. dup_f(in,out,mp)
  584. FILE *in;
  585. FILE *out;
  586. struct nntpsv *mp;
  587. /* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
  588. {
  589.     char *p;
  590.     int blank_line_flag = 1;
  591.  
  592.     for(;;) {
  593.         if (fgets(mp->buf,LineLen,in) == NULL)
  594.             return 0;
  595.  
  596.         if (blank_line_flag)
  597.             if (strnicmp(mp->buf,Hdrs[PATH],5) == 0) {
  598.                  p = strchr(mp->buf,' ') + 1;
  599.                  fprintf(out,"%s%s!%s",Hdrs[PATH],Host,p);
  600.                  continue;
  601.             }
  602.         /* oh oh - nntpserv is modifying articles....*/
  603.         if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
  604.             continue;
  605.         fputs(mp->buf,out);
  606.         if(!check_blank(mp->buf))
  607.             blank_line_flag = 0;
  608.     }
  609. }
  610.  
  611. /* returncode: < 1 if error; 1 success */
  612. static int
  613. dofwd(mp,f,history)
  614. struct nntpsv *mp;
  615. FILE *f;
  616. FILE *history;
  617. {
  618.     FILE *fwd;
  619.  
  620.     if(mp == NULLNNTPSV)
  621.         return -1;
  622.  
  623.     sprintf(mp->buf,"%s/fwd.seq",Newsdir);
  624.     if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
  625.         return -1;
  626.  
  627.     fgets(mp->buf,LineLen,fwd);
  628.     mp->hold_i = atoi(mp->buf) + 1;
  629.     fprintf(history," JUNK/%u",mp->hold_i);
  630.     rewind(fwd);
  631.     fprintf(fwd,"%u",mp->hold_i);
  632.     fclose(fwd);
  633.  
  634.     sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
  635.     if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
  636.         return -2;
  637.  
  638.     rewind(f);
  639.     dup_f(f,fwd,mp);
  640.     fclose(fwd);
  641.     return 1;
  642. }
  643.  
  644. #ifdef CONTROL
  645. static int
  646. docontrol(f,mp)
  647. FILE *f;
  648. struct nntpsv *mp;
  649. {
  650.     struct head *h;
  651.  
  652.     if(f == NULLFILE || mp == NULLNNTPSV
  653.       || (h = (struct head *)callocw(1,sizeof(struct head))) == NULLHEAD))
  654.         return -1;
  655.  
  656.     rewind(f);
  657.     h->subject = h->from = h->reply_to = h->id = NULLCHAR;
  658.  
  659.     for(;;) {
  660.         if ((fgets(mp->buf,LineLen,f)) == NULL)
  661.             break;
  662.         if (check_blank(mp->buf))
  663.             break;
  664.         rip2(mp->buf);
  665.         if (strncmp(mp->buf,Hdrs[SUBJECT],9) == 0)
  666.             h->subject = strdup(mp->buf);
  667.         if (strncmp(mp->buf,Hdrs[FROM],6) == 0)
  668.             h->from = strdup(mp->buf);
  669.         if (strnicmp(mp->buf,Hdrs[REPLYTO],10) == 0)
  670.             h->reply_to = strdup(mp->buf);
  671.         if (strnicmp(mp->buf,Hdrs[MSGID],12) == 0)
  672.             h->id = strdup(strchr(mp->buf,'<'));
  673.     }
  674.     if (h->subject != NULLCHAR)
  675.         if (strncmp(h->subject,"Subject: sendme ",16) == 0)
  676.             dosendme(h);
  677.     if (h->subject != NULLCHAR)
  678.         free(h->subject);
  679.     if (h->from != NULLCHAR)
  680.         free(h->from);
  681.     if (h->reply_to != NULLCHAR)
  682.         free(h->reply_to);
  683.     if (h->id != NULLCHAR)
  684.         free(h->id);
  685.     free((char *)h);
  686.     return 0;
  687. }
  688. #endif
  689.  
  690. static int
  691. xfer_article2(f,mp)
  692. FILE *f;
  693. struct nntpsv *mp;
  694. {
  695.     char line[LineLen], *p, *group = NULLCHAR, *p1, *from = NULLCHAR;
  696.     FILE *fptr, *history;
  697.     struct tm *stm;
  698.     int x;
  699. #ifdef CONTROL
  700.     int control = 0;
  701. #endif
  702.     long currtime;
  703.  
  704.     if(f == NULLFILE || mp == NULLNNTPSV ||
  705.       (history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE)
  706.         return -1;
  707.  
  708.     for (;;) {
  709.         if (fgets(line,LineLen,f) == NULL)
  710.             break;
  711.         rip2(line);
  712.         if (strnicmp(line,Hdrs[FROM],6) == 0) {
  713.             p = strchr(line,' ') + 1;
  714.             from = strdup(p);
  715.             continue;
  716.         }
  717.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0) {
  718.             p = strchr(line,' ') + 1;
  719.             group = strdup(p);
  720.             break;
  721.         }
  722.     }
  723.     time(&currtime);
  724.     stm = localtime(&currtime);
  725.     fprintf(history,"%s %2.2d%2.2d%2.2d %2.2d%2.2d%2.2d",
  726.         mp->id,
  727.         stm->tm_year,stm->tm_mon+1,stm->tm_mday,
  728.         stm->tm_hour,stm->tm_min,stm->tm_sec);
  729.  
  730.     mp->hold_i = 0;
  731.     p = group;
  732.     if((mp->ap = (struct article *)callocw(1,sizeof(struct article))) == NULLARTICLE)
  733.         goto quit;
  734.     x = 1;
  735.     while (x) {
  736.         if ((p1 = strchr(p,',')) != NULLCHAR) {
  737.             p1 = line;
  738.             while (*p != ',')
  739.                 *(p1++)=*(p++);
  740.             *p1 = '\0';
  741.             p++;
  742.             mp->ap->group = strdup(line);
  743.         } else {
  744.             mp->ap->group = strdup(p);
  745.             x = 0;
  746.         }
  747.         update_list(mp);
  748.         if (mp->ap->number > 0) {
  749.             get_path2(mp->ap);
  750.             mp->hold_i = 1;
  751.             sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
  752.             rewind(f);
  753.             if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  754.                 fclose(history);
  755.                 free(mp->ap->group);
  756.                 goto quit;
  757.             }
  758.             dup_f(f,fptr,mp);
  759.             fclose(fptr);
  760.             fprintf(history," %s/%d",mp->ap->group,mp->ap->number);
  761. #ifdef CONTROL
  762.             if (strcmp(mp->ap->group,"control") == 0)
  763.                 control = 1;
  764. #endif
  765.             free(mp->ap->path);
  766.         }
  767.         free(mp->ap->group);
  768.     }
  769.     if (mp->hold_i == 0) {
  770.         if ((x = dofwd(mp,f,history)) < 1)
  771.         mp->hold_i = 0;
  772.     }
  773.     fputc('\n',history);
  774.     fclose(history);
  775.     time(&currtime);
  776.     if(Nntpquiet < 2)
  777.         tprintf("New mail in newsgroup %s\n  from <%s> at %s%s",
  778.             group,from,ctime(&currtime),
  779.             (Nntpquiet < 1)  ? "\007" : "");
  780.  
  781. #ifdef CONTROL
  782.     if (control == 1)
  783.         docontrol(f,mp);
  784. #endif
  785. quit:
  786.     free(from);
  787.     free(group);
  788.     free((char *)mp->ap);
  789.     return 1;
  790. }
  791.  
  792. static void
  793. nntppoll(unused,cb1,p)
  794. int unused;
  795. void *cb1;
  796. void *p;
  797. {
  798.     char *cp, line[LineLen];
  799.     struct sockaddr_in fsocket;
  800.     struct nntpsv *cb;
  801.     struct tm *stm, *ltm;
  802.     FILE *f, *f1, *pf;
  803.     long t;
  804.     int r, now;
  805.     struct Servers *sp = (struct Servers *) cb1;
  806.     long currtime;
  807.  
  808.     if (!run_timer(&sp->nntpt))        /* if timer had stopped there is an
  809.         return;                         * active session */
  810.  
  811.     if (!Filecheck)
  812.         if(check_system())
  813.             return;
  814.  
  815.     if(availmem() < Memthresh) {
  816.         start_timer(&sp->nntpt);
  817.         return;
  818.     }
  819.  
  820.     /* check connection window */
  821.     time(&currtime);
  822.     ltm = localtime(&currtime);
  823.     now = ltm->tm_hour * 100 + ltm->tm_min;
  824.     if (sp->lowtime < sp->hightime) {
  825.         /* doesn't cross midnight */
  826.         if (now < sp->lowtime || now >= sp->hightime) {
  827.             start_timer(&sp->nntpt);
  828.             return;
  829.         }
  830.     } else {
  831.         if (now < sp->lowtime && now >= sp->hightime) {
  832.             start_timer(&sp->nntpt);
  833.             return;
  834.         }
  835.     }
  836.     if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
  837.       (cb = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  838.         start_timer(&sp->nntpt);
  839.         return;
  840.     }
  841.     stop_timer(&sp->nntpt);
  842.  
  843.     cb->fname = NULLCHAR;
  844.     cb->newnews = NULLCHAR;
  845.     rewind(pf);
  846.  
  847.     for(t = 0L; fgets(line,LineLen,pf) != NULLCHAR; t = ftell(pf)) {
  848.         if((cp = strchr(line,' ')) == NULLCHAR)
  849.             continue;        /* something wrong with this line, skip it */
  850.         *cp = '\0';
  851.         if(strnicmp(line,sp->name,strcspn(line," ")-1) == 0) {
  852.             rip2(cp+1);
  853.             cb->newnews = strdup(cp+1);
  854.             /* Prepare to write back the current host and date */
  855.             fseek(pf,t,0);
  856.             break;
  857.         }
  858.     }
  859.  
  860.     if(cb->newnews == NULLCHAR)
  861.          cb->newnews = strdup("800101 000000");
  862.  
  863.     fsocket.sin_family = AF_INET;
  864.     fsocket.sin_addr.s_addr = cb->dest = sp->dest;
  865.     fsocket.sin_port = IPPORT_NNTP;
  866.  
  867.     if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  868.         goto quit;
  869.     sockmode(cb->s,SOCK_ASCII);
  870.  
  871.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
  872.         goto quit;
  873.     log(cb->s,"Connect NNTP");
  874.  
  875.     time(&currtime);
  876.     stm = localtime(&currtime);
  877.  
  878.     if(getreply(cb) == -1)      /* throw away any hello msg */
  879.         goto quit;
  880.  
  881. #ifdef XXX
  882.     usputs(cb->s,"SLAVE\n");
  883.     if(getreply(cb) != 202)
  884.         goto quit;
  885. #endif
  886.     cb->slave = 1;
  887.  
  888.     if ((f = temp_file(0,1)) == NULLFILE)
  889.         goto quit;
  890.  
  891.     usprintf(cb->s,"NEWNEWS %s %s\n",sp->newsgroups,cb->newnews);
  892.     if(getreply(cb) != 230) {
  893.         fclose(f);
  894.         goto quit;
  895.     }
  896.     if(recv_file(f,cb->s) == -1) {
  897.         usprintf(cb->s,quitcmd);
  898.         fclose(f);
  899.         goto quit;
  900.     }
  901.     if ((f1 = temp_file(cb->s,1)) == NULLFILE) {
  902.         fclose(f);
  903.         goto quit;
  904.     }
  905.     rewind(f);
  906.  
  907.     for(;;) {
  908.         if (fgets(cb->buf,LineLen,f) == NULL)
  909.             break;
  910.         rip2(cb->buf);
  911.         if (strcmp(cb->buf,".") == 0)
  912.             break;
  913.         if (check_article(cb->buf) == 1)
  914.             continue;
  915.         usprintf(cb->s,"ARTICLE %s\n",cb->buf);
  916.         for (;;) {
  917.             if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
  918.                 break;
  919.             rip2(cb->buf);
  920.             if(!isdigit(cb->buf[0])) {
  921.                 r = -1;
  922.                 continue;
  923.             } else {
  924.                 r = atoi(cb->buf);
  925.                 break;
  926.             }
  927.         }
  928.         if(r == -1)
  929.             break;
  930.         if (r == 220) {
  931.             recv_file(f1,cb->s);
  932.             rewind(f1);
  933.             for ( ;; ) {
  934.                 if (fgets(cb->buf,LineLen,f1) == NULL)
  935.                     break;
  936.                 rip2(cb->buf);
  937.                 if (strnicmp(cb->buf,Hdrs[MSGID],12) == 0) {
  938.                     cb->id = strdup((strchr(cb->buf,' ')) + 1);
  939.                     break;
  940.                 }
  941.             }
  942.             rewind(f1);
  943.             xfer_article2(f1,cb);
  944.             free(cb->id);
  945.         }
  946.         fclose(f1);
  947.         if ((f1 = temp_file(cb->s,1)) == NULLFILE)
  948.             goto quit;
  949.     }
  950.     fclose(f);
  951.     fclose(f1);
  952.     usprintf(cb->s,quitcmd);
  953.     if (recvline(cb->s,cb->buf,LineLen) == -1)
  954.         goto quit;
  955. quit:
  956.     if(errno == 0) {
  957.         /* Now write back the opening date and time */
  958.         fprintf(pf,"%s %02d%02d%02d %02d%02d%02d\n",
  959.             sp->name,
  960.             stm->tm_year,
  961.             stm->tm_mon + 1,
  962.             stm->tm_mday,
  963.             stm->tm_hour,
  964.             stm->tm_min,
  965.             stm->tm_sec);
  966.     }
  967.     fclose(pf);
  968.  
  969.     close_s(cb->s);
  970.     free(cb->newnews);
  971.     free((char *)cb);
  972.     start_timer(&sp->nntpt);
  973. }
  974.  
  975. static int
  976. ngmatcha(func,dflt,ngspec,matchlist)
  977. int    (*func)();
  978. int    dflt;
  979. struct g_list *ngspec;
  980. struct g_list *matchlist;
  981. {
  982.     register int    match;
  983.     char   *cp;
  984.     struct g_list    *m,*n;
  985.  
  986.     match = dflt;
  987.     m = matchlist;
  988.     for(;;) {
  989.         if ((cp = strchr(m->str,'/')) != NULLCHAR)
  990.             *cp = '\0';
  991.         n = ngspec;
  992.         for (;;) {
  993.             if (n->str[0] == '!') {      /* Handle negation */
  994.                 if ((*func)(n->str+1, m->str)) {
  995.                     match = 0;
  996.                 }
  997.             } else {
  998.                 if ((*func)(n->str, m->str)) {
  999.                     match = 1;
  1000.                 }
  1001.             }
  1002.             if (n->next == NULLG)
  1003.                 break;
  1004.             else
  1005.                 n=n->next;
  1006.         }
  1007.         if (m->next == NULLG)
  1008.             break;
  1009.         else
  1010.             m=m->next;
  1011.     }
  1012.     return (match);
  1013. }
  1014.  
  1015. static int
  1016. restreql(w, s)
  1017. register char *w;
  1018. register char *s;
  1019. {
  1020.     while (*s && *w) {
  1021.         switch (*w) {
  1022.             case '*':
  1023.                 for (w++; *s; s++)
  1024.                     if (restreql(w, s))
  1025.                         return 1;
  1026.                 break;
  1027.             default:
  1028.                 if (*w != *s)
  1029.                     return 0;
  1030.                 w++, s++;
  1031.                 break;
  1032.         }
  1033.     }
  1034.     if (*s)
  1035.         return 0;
  1036.     while (*w)
  1037.         if (*w++ != '*')
  1038.             return 0;
  1039.  
  1040.     return 1;
  1041. }
  1042.  
  1043. /* converts timestring to unix-compatible structure
  1044.  * returncode: 0 (!!) if error; > 0 success */
  1045. static int32
  1046. make_nntime(d,t,str)
  1047. struct date *d;
  1048. struct time *t;
  1049. char *str;
  1050. {
  1051.     register char *cp;
  1052.     char tmp[3];
  1053.  
  1054.     if(str == NULLCHAR)
  1055.         return 0;
  1056.  
  1057.     tmp[2] = '\0';
  1058.     cp = str;
  1059.  
  1060.     strncpy(tmp,cp,2);
  1061.  
  1062.     d->da_year = atoi(tmp)+1900;
  1063.  
  1064.     if (d->da_year < 1980)
  1065.         d->da_year = 1980;
  1066.  
  1067.     if (d->da_year > 2099)
  1068.         goto quit;
  1069.  
  1070.     cp+=2;
  1071.  
  1072.     strncpy(tmp,cp,2);
  1073.     d->da_mon = atoi(tmp);
  1074.     if (d->da_mon < 1 || d->da_mon > 12)
  1075.         goto quit;
  1076.  
  1077.     cp+=2;
  1078.  
  1079.     strncpy(tmp,cp,2);
  1080.     d->da_day = atoi(tmp);
  1081.     if (d->da_day < 1 || d->da_day > 32)
  1082.         goto quit;
  1083.  
  1084.     cp+=3;
  1085.  
  1086.     strncpy(tmp,cp,2);
  1087.     t->ti_hour = atoi(tmp);
  1088.     if (t->ti_hour < 0 || t->ti_hour > 24)
  1089.         goto quit;
  1090.  
  1091.     cp+=2;
  1092.  
  1093.     strncpy(tmp,cp,2);
  1094.     t->ti_min = atoi(tmp);
  1095.     if (t->ti_min < 0 || t->ti_min > 60)
  1096.         goto quit;
  1097.  
  1098.     cp+=2;
  1099.  
  1100.     strncpy(tmp,cp,2);
  1101.     t->ti_sec = atoi(tmp);
  1102.     if (t->ti_sec < 0 || t->ti_sec > 60)
  1103.         goto quit;
  1104.  
  1105.     t->ti_hund = 0;
  1106.     return (dostounix(d,t));
  1107. quit :
  1108.     return 0L;
  1109. }
  1110.  
  1111. /* returncode: -1 if error; 0 if no new news; 1 new news available */
  1112. static int
  1113. newnews(string,mp,f)
  1114. char *string;
  1115. struct nntpsv *mp;
  1116. FILE *f;
  1117. {
  1118.     register int i,j;
  1119.     char *cp, *cp1, line[LineLen], groups[LineLen];
  1120.     struct g_list *ng, *hist, *ngp, *histp, *ptr;
  1121.     FILE *f1;
  1122.     int all = 1;
  1123.  
  1124.     if (check_one(string) == -1)
  1125.         return -1;
  1126.  
  1127.     cp = string;
  1128.     i = 1;
  1129.  
  1130.     while (*(cp++) > 32)
  1131.         i++;
  1132.     if (strlen(cp) < 13)
  1133.         return -1;
  1134.  
  1135.     strncpy(groups,string,i-1);
  1136.     groups[i-1] = '\0';
  1137.     if(strcmp(groups,"*") != 0)
  1138.         all = 0;
  1139.  
  1140.     mp->datest = (struct date *)callocw(1,sizeof(struct date));
  1141.     mp->timest = (struct time *)callocw(1,sizeof(struct time));
  1142.     gettime(mp->timest);
  1143.     getdate(mp->datest);
  1144.  
  1145.     if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) == 0)
  1146.         goto quit;
  1147.     if (mp->unixtime == -1L)
  1148.         return 0;
  1149.  
  1150.     if (!all) {
  1151.         ng = ngp = (struct g_list *)callocw(1,(sizeof(struct g_list)));
  1152.         cp = groups;
  1153.  
  1154.         for (;;) {
  1155.             if ((cp1 = strchr(cp,',')) == NULLCHAR ) {
  1156.                 ng->str = strdup(cp);
  1157.                 ng->next = NULLG;
  1158.                 break;
  1159.             }
  1160.             j = strcspn(cp,",");
  1161.             ng->str = (char *)callocw(1,j+1);
  1162.             strncpy(ng->str,cp,j);
  1163.             ng->str[j] = '\0';
  1164.             ng->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1165.             ng = ng->next;
  1166.             cp1 = strchr(cp,',');
  1167.             if (cp1 != NULLCHAR)
  1168.                 cp = cp1 + 1;
  1169.             else
  1170.                 break;
  1171.         }
  1172.     }
  1173.  
  1174.     if ((f1 = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1175.         goto quit;
  1176.  
  1177.     for (;;) {
  1178.         if (fgets(line,LineLen,f1) == NULL)
  1179.             break;
  1180.         rip2(line);
  1181.  
  1182.         if (!all) {
  1183.             for(i = 3, cp = line; i; --i)
  1184.                 cp = strchr(cp,' ') + 1;
  1185.             histp = (struct g_list *)callocw(1,sizeof(struct g_list));
  1186.             hist = histp;
  1187.  
  1188.             for (;;) {
  1189.                 if ((cp1 = strchr(cp,' ')) == NULLCHAR) {
  1190.                     hist->str = strdup(cp);
  1191.                     hist->next = NULLG;
  1192.                     break;
  1193.                 }
  1194.  
  1195.                 j = strcspn(cp," ");
  1196.                 hist->str = (char *)callocw(1,j+1);
  1197.                 strncpy(hist->str,cp,j);
  1198.                 hist->str[j] = '\0';
  1199.                 hist->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1200.                 hist = hist->next;
  1201.                 cp1 = strchr(cp,' ');
  1202.                 if (cp1 != NULLCHAR)
  1203.                     cp = cp1 + 1;
  1204.                 else
  1205.                     break;
  1206.             }
  1207.             if (!ngmatcha(restreql,0,ngp,histp)) {
  1208.                 ptr = histp;
  1209.                     for (;;) {
  1210.                         ptr = histp->next;
  1211.                         free(histp->str);
  1212.                         free(histp);
  1213.                         histp = ptr;
  1214.                         if (histp == NULLG)
  1215.                             break;
  1216.                     }
  1217.                 continue;
  1218.             }
  1219.         }
  1220.         cp = strchr(line,' ') + 1;
  1221.         if ((mp->ftime = make_nntime(mp->datest,mp->timest,cp)) == 0) {
  1222.             fclose(f1);
  1223.             goto quit;
  1224.         }
  1225.         if ((mp->ftime - mp->unixtime) > 0) {
  1226.             cp = line;
  1227.             while ( *cp > 32 )
  1228.                 fputc(*(cp++),f);
  1229.             fputc('\n',f);
  1230.         }
  1231.         if (!all) {
  1232.             ptr = histp;
  1233.             for (;;) {
  1234.                 ptr = histp->next;
  1235.                 free(histp->str);
  1236.                 free(histp);
  1237.                 histp = ptr;
  1238.                 if (histp == NULLG)
  1239.                     break;
  1240.             }
  1241.         }
  1242.     }
  1243.     fclose(f1);
  1244.     if (!all) {
  1245.         ptr = ngp;
  1246.         for (;;) {
  1247.             ptr = ngp->next;
  1248.             free(ngp->str);
  1249.             free(ngp);
  1250.             ngp = ptr;
  1251.             if (ngp == NULLG)
  1252.                 break;
  1253.         }
  1254.     }
  1255.     free(mp->datest);
  1256.     free(mp->timest);
  1257.     return 1;
  1258. quit:
  1259.     return 0;
  1260. }
  1261.  
  1262. /* handles incoming newnews-cmd
  1263.  * returncode: -1 if error; 0 no groups or bad syntax; 1 success */
  1264. static int
  1265. donewnews(string,mp)
  1266. char *string;
  1267. struct nntpsv *mp;
  1268. {
  1269.     FILE *f;
  1270.     int ret;
  1271.  
  1272.     if((f = temp_file(mp->s,1)) == NULLFILE)
  1273.         return -1;
  1274.  
  1275.     ret = newnews(string,mp,f);
  1276.  
  1277.     switch(ret) {
  1278.     case -1:                        /* error in "newnews" routine */
  1279.         ret = 0;
  1280.         usputs(mp->s,badsyntax);
  1281.         break;
  1282.     case 0:                         /* no new news */
  1283.         usputs(mp->s,newnews_t);
  1284.         usputs(mp->s,NEol);
  1285.         break;
  1286.     default:                        /* new news available, send news file */
  1287.         rewind(f);
  1288.         usputs(mp->s,newnews_t);
  1289.         sendfile(f,mp->s,ASCII_TYPE,0);
  1290.         usputs(mp->s,NEol);
  1291.         ret = 1;
  1292.         break;
  1293.     }
  1294.     fclose(f);
  1295.     return ret;
  1296. }
  1297.  
  1298. /* change current newsgroup
  1299.  * returncode: -1 if error; 0 success; 1 no newsgroup */
  1300. static int
  1301. dogroup(mp,buf)
  1302. struct nntpsv *mp;
  1303. char *buf;
  1304. {
  1305.     char *p;
  1306.     int er;
  1307.  
  1308.     if((p = strchr(buf,' ')) == NULLCHAR)
  1309.         return -1;
  1310.  
  1311.     er = get_path(p,mp);
  1312.  
  1313.     switch (er) {
  1314.     case 0:
  1315.         usputs(mp->s,nogroup);
  1316.         return 1;
  1317.     default:
  1318.         p = strchr(buf,' ');
  1319.         if (get_pointer(p,mp) == 1) {
  1320.             usprintf(mp->s,listarticle,
  1321.                 mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
  1322.             return 0;
  1323.         }
  1324.     case -1:
  1325.         usputs(mp->s,error);
  1326.         return -1;
  1327.     }
  1328. }
  1329.  
  1330.  
  1331. /* checks if newsgroup is selected
  1332.  * returncode: -1 no group selected; 0 success */
  1333. static int
  1334. check_grp(mp)
  1335. struct nntpsv *mp;
  1336. {
  1337.     if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
  1338.         usputs(mp->s,noselect);
  1339.         return -1;
  1340.     }
  1341.     return 0;
  1342. }
  1343.  
  1344. /* get id-number of message
  1345.  * returncode: -1 if error; 0 if no message; 1 success */
  1346. static int
  1347. get_id(bp,mp)
  1348. char *bp;
  1349. struct nntpsv *mp;
  1350. {
  1351.     FILE *f;
  1352.     char tmp[LineLen];
  1353.  
  1354.     if ((f = open_message(mp,NULLFILE)) == NULLFILE)
  1355.         return 0;
  1356.  
  1357.     for (;;) {
  1358.         if (fgets(tmp,LineLen,f) == NULL)
  1359.             break;
  1360.         if (check_blank(tmp))
  1361.             break;
  1362.         if (strnicmp(tmp,Hdrs[MSGID],12)==0) {
  1363.             fclose(f);
  1364.             strcpy(bp,strchr(tmp,' '));
  1365.             rip2(bp);
  1366.             return 1;
  1367.         }
  1368.     }
  1369.     fclose(f);
  1370.     strcpy(bp,"\0");
  1371.     return 0;
  1372. }
  1373.  
  1374. /* gets next news of newsgroup
  1375.  * returncode: -1 if error; 0 no news; 1 success */
  1376. static int
  1377. get_next(mp)
  1378. struct nntpsv *mp;
  1379. {
  1380.     FILE *f;
  1381.  
  1382.     for (;;) {
  1383.         if (mp->pointer == 0 ) {
  1384.             usputs(mp->s,nonext);
  1385.             return 0;
  1386.         }
  1387.         if (++(mp->pointer) > mp->last) {
  1388.             mp->pointer--;
  1389.             usputs(mp->s,nonext);
  1390.             return 0;
  1391.         }
  1392.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1393.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1394.             fclose(f);
  1395.             return 1;
  1396.         }
  1397.     }
  1398. }
  1399.  
  1400. /* gets last news of newsgroup
  1401.  * returncode: -1 if error; 0 no news; 1 success */
  1402. static int
  1403. get_last(mp)
  1404. struct nntpsv *mp;
  1405. {
  1406.     FILE *f;
  1407.  
  1408.     for (;;) {
  1409.         if (mp->pointer == 0) {
  1410.             usputs(mp->s,noprev);
  1411.             return 0;
  1412.         }
  1413.         if (--(mp->pointer) < mp->first) {
  1414.             mp->pointer++;
  1415.             usputs(mp->s,noprev);
  1416.             return 0;
  1417.         }
  1418.         sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1419.         if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1420.             fclose(f);
  1421.             return 1;
  1422.         }
  1423.     }
  1424. }
  1425.  
  1426. static int
  1427. art_ret(mp)
  1428. struct nntpsv *mp;
  1429. {
  1430.     if(get_id(mp->buf,mp) == -1)
  1431.         return -1;
  1432.     return usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
  1433. }
  1434.  
  1435. static int
  1436. doarticle(buf,mp)   /* Sends article <message-id> to the client */
  1437. char *buf;
  1438. struct nntpsv *mp;
  1439. {
  1440.     FILE *f;
  1441.     char *p, *p2, *holds, line[LineLen];
  1442.  
  1443.     if((p = strchr(buf,'<')) == NULLCHAR
  1444.      || (f = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1445.         return 0;
  1446.  
  1447.     for(;;) {
  1448.         if (fgets(line,LineLen,f) == NULL)
  1449.             break;
  1450.         if (strstr(line,p) != NULL) {
  1451.             fclose(f);
  1452.  
  1453.             p = (strchr(line,' ')) + 14;      /* point to the first newsgroup */
  1454.             p2 = strchr(p,'/');                  /* point to article number */
  1455.             mp->hold_i = mp->pointer;       /* save current pointer */
  1456.             holds = strdup(mp->path);      /* save path of current article */
  1457.             mp->pointer = atoi((p2 + 1));     /* get the article number */
  1458.  
  1459.             if (mp->path != NULLCHAR) {
  1460.                 free(mp->path);
  1461.                 mp->path='\0';
  1462.             }
  1463.  
  1464.             *p2 = '\0';
  1465.             rip2(p);
  1466.  
  1467.             if (strncmp(p+1,"JUNK",6) == 0) {
  1468.                 sprintf(mp->buf,"%s",Forward);
  1469.                 mp->path = strdup(mp->buf);
  1470.             } else
  1471.                 get_path(p,mp);
  1472.  
  1473.             if ((f = open_message(mp,f)) == NULLFILE) {
  1474.                 usputs(mp->s,error);
  1475.                 return 0;
  1476.             }
  1477.             art_ret(mp);
  1478.             sendfile(f, mp->s, ASCII_TYPE,0);
  1479.             fclose(f);
  1480.             usputs(mp->s,NEol);
  1481.             free(mp->path);
  1482.             mp->path=strdup(holds);
  1483.             mp->pointer=mp->hold_i;
  1484.             free(holds);
  1485.             return 1;
  1486.         }
  1487.  
  1488.     }
  1489.     fclose(f);
  1490.     usputs(mp->s,noart);
  1491.     return 0;
  1492. }
  1493.  
  1494. /* checks for a minimum header
  1495.  * returncode: -1 if error; 0 complete; 1 not complete */
  1496. static int
  1497. garbled(f)
  1498. FILE *f;
  1499. {
  1500. /*
  1501.  * The minimum requirement for an incoming article is that it must have
  1502.  * a newsgroups: line, a message-id: line, and a blank line.  This is
  1503.  * pretty forgiving.
  1504.  */
  1505.     char line[LineLen];
  1506.     int ok = 0;
  1507.  
  1508.     rewind(f);
  1509.     for(;;) {
  1510.         if (fgets(line,LineLen,f) == NULL)
  1511.             break;
  1512.         if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0)
  1513.             ok |= 1;
  1514.         if (strnicmp(line,Hdrs[MSGID],12) == 0)
  1515.             ok |= 2;
  1516.         if (ok == 3)
  1517.             break;
  1518.         if (check_blank(line))
  1519.             break;
  1520.     }
  1521.     rewind(f);
  1522.     return (ok == 3) ? 0 : 1;
  1523. }
  1524.  
  1525. /* returncode: -1 if error; 0 success */
  1526. static int
  1527. get_article2(mp, id)
  1528. struct nntpsv *mp;
  1529. char *id;
  1530. {
  1531.     FILE *f;
  1532.     int ret = -1;
  1533.  
  1534.     if((f = temp_file(0,1)) == NULLFILE)
  1535.         return -1;
  1536.  
  1537.     mp->ap = (struct article *)callocw(1,sizeof(struct article));
  1538.     mp->id = strdup(id);
  1539.     usputs(mp->s,sendart);
  1540.  
  1541.     if(recv_file(f,mp->s) == (-1)) {
  1542.         free((struct article *)mp->ap);    /* yc1dav */
  1543.         goto quit;
  1544.         }
  1545.     if ((ret = garbled(f)) != 0) {
  1546.         usputs(mp->s,transnotok);
  1547.         free((struct article *)mp->ap);    /* yc1dav */
  1548.         goto quit;
  1549.         }
  1550.     if(xfer_article2(f,mp) == 0)
  1551.         goto quit;
  1552.     usputs(mp->s,transok);
  1553.  
  1554. /*     free_ap(mp);             <------------ */
  1555. quit:
  1556. /*  free((char *)mp->ap);  <------------ */
  1557. /*    free(mp->id);      <----- yc1dav */
  1558.     fclose(f);
  1559.     return ret;
  1560. }
  1561.  
  1562. void
  1563. poll(p)
  1564. void *p;
  1565. {
  1566.     newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0);
  1567. }
  1568.  
  1569. static void
  1570. nntpserv(s,unused,p)
  1571. int s;
  1572. void *unused;
  1573. void *p;
  1574. {
  1575.     struct nntpsv *mp;
  1576.     FILE *fp;
  1577.     long t;
  1578.     int cnt;
  1579.     char **cmdp, *arg, *cp, *cmd, buf[LineLen];
  1580.  
  1581.     sockmode(s,SOCK_ASCII);
  1582.     sockowner(s,Curproc);        /* We own it now */
  1583.     log(s,"open NNTP");
  1584.  
  1585.     if (!Filecheck)
  1586.         if(check_system()) {
  1587.             usprintf(s,fatal,"STRUCTURE");
  1588.             log(s,"NNTP error - FILE STRU");
  1589.             close_s(s);
  1590.             return;
  1591.         }
  1592.     if((mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  1593.         usprintf(s,Nospace);
  1594.         close_s(s);
  1595.         return;
  1596.     }
  1597.     mp->s = s;
  1598.     mp->debug = 0;
  1599.     mp->path = NULLCHAR;
  1600.  
  1601.     time(&t);
  1602.     cp = ctime(&t);
  1603.     cp[24] = '\0';
  1604.  
  1605.     usprintf(s,nnversion,(Filecheck) ? "0" : "1",Host,Version,cp);
  1606.  
  1607. loop:
  1608.     if ((cnt = recvline(s,buf,LineLen)) == -1) {
  1609.         /* He closed on us */
  1610.         goto quit;
  1611.     }
  1612.     rip2(buf);
  1613.     cmd = buf;
  1614.  
  1615.     /* Translate entire buffer to lower case */
  1616.     for(cp = cmd; *cp != '\0' ;cp++) {
  1617.         if ( *cp == ' ' ) break;
  1618.         *cp = tolower(*cp);
  1619.     }
  1620.     /* Find command in table; if not present, return syntax error */
  1621.     for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  1622.         if(strnicmp(*cmdp,cmd,min(strlen(*cmdp),strlen(cmd))) == 0)
  1623.             break;
  1624.  
  1625.     if(*cmdp == NULLCHAR){
  1626.         usputs(mp->s,badsyntax);
  1627.         goto loop;
  1628.     }
  1629.     arg = &cmd[strlen(*cmdp)];
  1630.  
  1631.     /* Skip spaces after command */
  1632.     while(*arg == ' ')
  1633.         arg++;
  1634.  
  1635.     /* Execute specific command */
  1636.     switch(cmdp - commands) {
  1637.     case QUIT_CMD:
  1638.         goto quit;
  1639.     case NEWNEWS_CMD:
  1640.         if ((cp = strchr(buf,' ')) == NULLCHAR) {
  1641.             usputs(mp->s,badsyntax);
  1642.             break;
  1643.         }
  1644.         cp++;
  1645.         donewnews(cp,mp);
  1646.         break;
  1647.     case IHAVE_CMD:
  1648.         if ((cp = strchr(buf,'<')) == NULLCHAR) {
  1649.             usputs(mp->s,badsyntax);
  1650.             break;
  1651.         }
  1652.         if (check_article(cp) == 1) {
  1653.             usputs(mp->s,notwanted);
  1654.             break;
  1655.         }
  1656.         if(get_article2(mp,cp))
  1657.             goto quit;
  1658.         break;
  1659.     case HELP_CMD:
  1660.         usprintf(mp->s,"100 %s - help follows:\n",Host);
  1661.         if ((fp = open_file(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
  1662.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1663.             fclose(fp);
  1664.         } else {
  1665.             usputs(mp->s,help);
  1666.         }
  1667.         usputs(mp->s,NEol);
  1668.         break;
  1669.     case XINFO_CMD:
  1670.         if ((fp = open_file(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
  1671.             usprintf(mp->s,"100 %s - xinfo follows:\n",Host);
  1672.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1673.             fclose(fp);
  1674.         } else {
  1675.             usputs(mp->s,xinfo);
  1676.         }
  1677.         usputs(mp->s,NEol);
  1678.         break;
  1679.     case LIST_CMD:
  1680.         if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
  1681.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1682.             fclose(fp);
  1683.             usputs(mp->s,NEol);
  1684.         }
  1685.         break;
  1686.     case GROUP_CMD :
  1687.         dogroup(mp,&buf[0]);
  1688.         break;
  1689.     case HEAD_CMD : {
  1690.         if (check_grp(mp))
  1691.             break;
  1692.         if (get_id(mp->buf,mp) == 0)
  1693.             break;
  1694.         usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
  1695.         if ((fp = open_message(mp,fp)) == NULLFILE)
  1696.             break;
  1697.         for (;;) {
  1698.             if ((fgets(mp->buf,LineLen,fp)) == NULL)
  1699.                 break;
  1700.             if (check_blank(mp->buf))
  1701.                 break;
  1702.             usprintf(mp->s,"%s",mp->buf);
  1703.         }
  1704.         fclose(fp);
  1705.         usputs(mp->s,NEol);
  1706.         break;
  1707.     }
  1708.     case BODY_CMD : {
  1709.         if (check_grp(mp))
  1710.             break;
  1711.         if (get_id(mp->buf,mp) == 0)
  1712.             break;
  1713.         usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
  1714.         if ((fp = open_message(mp,fp)) == NULLFILE)
  1715.             break;
  1716.         mp->hold_i = 0;
  1717.         for (;;) {
  1718.             if ((fgets(mp->buf,LineLen,fp)) == NULL)
  1719.                 break;
  1720.             if (mp->hold_i)
  1721.                 usputs(mp->s,mp->buf);
  1722.             if (check_blank(mp->buf))
  1723.                 mp->hold_i = 1;
  1724.         }
  1725.         fclose(fp);
  1726.         usputs(mp->s,NEol);
  1727.         break;
  1728.     }
  1729.     case STAT_CMD : {
  1730.         if (check_grp(mp))
  1731.             break;
  1732.         if (get_id(mp->buf,mp) == 0)
  1733.             break;
  1734.         usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
  1735.         break;
  1736.     }
  1737.     case ARTICLE_CMD : {
  1738.         if (strchr(buf,'<') != NULLCHAR) {
  1739.           doarticle(buf,mp);
  1740.           break;
  1741.         }
  1742.         if (check_grp(mp))
  1743.             break;
  1744.         cp = strchr(buf,'e');
  1745.         cp++;
  1746.         if ((cnt < 9 ) || (check_blank(cp))) {
  1747.             if ((fp = open_message(mp,fp)) == NULLFILE)
  1748.                 break;
  1749.             art_ret(mp);
  1750.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1751.             fclose(fp);
  1752.             usputs(mp->s,NEol);
  1753.             break;
  1754.         }
  1755.         if ((cp = strpbrk(buf,"0123456789")) != NULLCHAR) {
  1756.             cnt = atoi(cp);
  1757.             if ((cnt > mp->last) || ( cnt < mp->first)) {
  1758.                 usputs(mp->s,noart);
  1759.                 break;
  1760.             }
  1761.             mp->pointer = cnt;
  1762.             if ((fp = open_message(mp,fp)) == NULLFILE)
  1763.                 break;
  1764.             art_ret(mp);
  1765.             sendfile(fp,mp->s,ASCII_TYPE,0);
  1766.             fclose(fp);
  1767.             usputs(mp->s,NEol);
  1768.             break;
  1769.         }
  1770.         break;
  1771.     }
  1772.     case NEXT_CMD : {
  1773.         if (check_grp(mp))
  1774.             break;
  1775.         if (get_next(mp) == 1) {
  1776.             if (get_id(buf,mp) == 1)
  1777.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  1778.             break;
  1779.         }
  1780.         break;
  1781.     }
  1782.     case LAST_CMD :
  1783.         if (check_grp(mp))
  1784.             break;
  1785.         if (get_last(mp) == 1 ) {
  1786.             if (get_id(buf,mp) == 1)
  1787.                 usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  1788.             break;
  1789.         }
  1790.         break;
  1791.     /* This two following cmds currently are not used for much */
  1792.     case DEBUG_CMD:
  1793.         mp->debug = (mp->debug == 0) ? 1 : 0;
  1794.         usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
  1795.         break;
  1796.     case SLAVE_CMD :
  1797.         mp->slave = (mp->slave == 0) ? 1 : 0;
  1798.         usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
  1799.         break;
  1800.     }
  1801.     goto loop;
  1802.  
  1803. quit:
  1804.     usputs(mp->s,closing);
  1805.     log(mp->s,"close NNTP");
  1806.     close_s(mp->s);
  1807.     if(mp->path != NULLCHAR)
  1808.         free(mp->path);
  1809.     if(mp->newnews != NULLCHAR)
  1810.         free(mp->newnews);
  1811.     if(mp->fname != NULLCHAR)
  1812.         free(mp->fname);
  1813.     if(mp->id != NULLCHAR);
  1814.         free(mp->id);
  1815.     free((char *)mp);
  1816. }
  1817.  
  1818. /* ---------------------------- NNTP-GATE --------------------------- */
  1819.  
  1820. #ifdef MSDOS
  1821. static char * near
  1822. #else
  1823. static char *
  1824. #endif
  1825. mkreplypath(data)
  1826. FILE *data;
  1827. {
  1828.     char buf[LINELEN], *cp, *cp1, *path;
  1829.  
  1830.     sprintf(buf,"%sNNTP_GATE@%s",Hdrs[PATH],Hostname);
  1831.     path = strdup(buf);
  1832.     rewind(data);
  1833.     while((fgets(buf,LINELEN,data)) != 0) {
  1834.         if(htype(buf) == DATE)
  1835.             break;
  1836.         if(htype(buf) == RECEIVED) {
  1837.             cp = strchr(buf,' ');
  1838.             cp++;
  1839.             cp = strchr(cp, ' ');
  1840.             cp++;
  1841.             cp1 = strpbrk(cp, ". \0");
  1842.             *cp1 = '\0';
  1843.             cp1 = mallocw(strlen(path)+strlen(cp)+2);  /* */
  1844.             sprintf(cp1,"%s!%s",path,cp);
  1845.             free(path);
  1846.             path = cp1;
  1847.         }
  1848.     }
  1849.     return(path);
  1850. }
  1851.  
  1852. int
  1853. nnGpost(data, from, le)
  1854. FILE *data;
  1855. char *from;
  1856. struct list *le;
  1857. {
  1858.     struct nntpsv *mp;
  1859.     char buf[LINELEN], *cp;
  1860.     FILE *f, *idf;
  1861.     int32 id;
  1862.     int strl; /* yc1dav */
  1863.     long currtime;
  1864.  
  1865.     if (!Filecheck)
  1866.         if(check_system())
  1867.             return -1;
  1868.  
  1869.     if ((f = temp_file(0,1)) == NULLFILE)
  1870.         return -1;
  1871.  
  1872.     mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  1873.  
  1874.     /* build postuser */
  1875.     cp = mkreplypath(data);
  1876.     fprintf(f,"%s\n",cp);
  1877.     free((char *)cp);
  1878.     fprintf(f,"%s%s\n",Hdrs[FROM],from);
  1879.     /*----------------------------------------------------------------*
  1880.     * build newsgroup                                                 *
  1881.     *-----------------------------------------------------------------*/
  1882.     if((cp = strchr(le->val,'@')) != NULLCHAR)
  1883.         *cp = '\0';
  1884.     strcpy(cp,le->val);
  1885.     strl = strlen(cp);
  1886.     while(*cp != '\0') {
  1887.         if(*cp == '!') *cp = '.'; /* change ! into . - yc1dav */
  1888.         cp++;
  1889.     }
  1890.     fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],(cp-strl+1));     /* skip the first "." */
  1891.     /*----------------------------------------------------------------*
  1892.     * find the subject
  1893.     *-----------------------------------------------------------------*/
  1894.     rewind (data);
  1895.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1896.         if (htype(buf)== SUBJECT)
  1897.             break;
  1898.         continue;
  1899.     }
  1900.     fputs((*buf == 0) ? "Subject: (none)\n" : buf,f);
  1901.     /*-------------------------------------------------------------------*
  1902.     * use msgid of original message
  1903.     *--------------------------------------------------------------------*/
  1904.     rewind(data);
  1905.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1906.         if (htype(buf)== MSGID)
  1907.             break;
  1908.         continue;
  1909.     }
  1910.     if (*buf == 0)   {
  1911.         sprintf(buf,"%s/sequence.seq",Mailqdir);
  1912.         idf = open_file(buf,"r+",0,1);
  1913.         id = atol(fgets(buf,LineLen,idf));
  1914.         rewind(idf);
  1915.         fprintf(idf,"%ld",id+2);
  1916.         fclose(idf);
  1917.         fprintf(f,"%s<%ld@%s>\n",Hdrs[MSGID],id,Hostname);
  1918.         sprintf(mp->buf,"<%ld@%s>",id,Hostname);
  1919.     } else {
  1920.         fputs(buf,f);
  1921.         rip(buf);
  1922.         cp = strchr(buf,'<');
  1923.         strcpy(mp->buf,cp);
  1924.         if (check_article(mp->buf))
  1925.             goto quit;
  1926.     }
  1927.     rewind (data);
  1928.     time(&currtime);
  1929.     fprintf(f,"Sender: NNTP@%s\n",Hostname);
  1930.     /*-------------------------------------------------------------------*
  1931.     * message follows                                                    *
  1932.     *--------------------------------------------------------------------*/
  1933.     fputs("Comments: Message transferred from SMTP\n",f);
  1934.     while((fgets(buf,sizeof(buf),data))!=0)   {
  1935.         switch(htype(buf))   {
  1936.             case FROM:
  1937.             case MSGID:
  1938.             case RECEIVED:
  1939.                 fgets(buf,sizeof(buf),data); /*eat the id*/
  1940.                 continue;
  1941.         }
  1942.         fputs(buf,f);
  1943.     }
  1944.     rewind(f);
  1945.     mp->id = strdup(mp->buf);
  1946.     xfer_article2(f,mp);
  1947. /*
  1948.     log(-1,"NNGT: transfer: Msg %s",mp->id);
  1949. */
  1950. quit:
  1951.     fclose(f);
  1952.     free(mp);
  1953.     return 0;
  1954. }
  1955.  
  1956. /* ---------------------------- Servercmd --------------------------- */
  1957.  
  1958. /* Start up NNTP receiver service */
  1959. int
  1960. nntp1(argc,argv,p)
  1961. int argc;
  1962. char *argv[];
  1963. void *p;
  1964. {
  1965.     struct sockaddr_in lsocket;
  1966.     int s;
  1967.  
  1968.     if(Snntp != -1)
  1969.         return -1;
  1970.     if(check_system() == -1)
  1971.         return -1;
  1972.  
  1973.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  1974.     chname(Curproc,"NNTP listener");
  1975.  
  1976.     lsocket.sin_family = AF_INET;
  1977.     lsocket.sin_addr.s_addr = INADDR_ANY;
  1978.     lsocket.sin_port = (argc < 2) ? IPPORT_NNTP : atoi(argv[1]);
  1979.  
  1980.     Snntp = socket(AF_INET,SOCK_STREAM,0);
  1981.     bind(Snntp,(char *)&lsocket,sizeof(lsocket));
  1982.     listen(Snntp,1);
  1983.  
  1984.     for(;;){
  1985.         if((s = accept(Snntp,NULLCHAR,(int *)NULL)) == -1)
  1986.             break;    /* Service is shutting down */
  1987.  
  1988.         /* Low mem check now done in tcpin.c - WG7J */
  1989.         sockmode(s,SOCK_ASCII);
  1990.         /* Spawn a server */
  1991.         newproc("NNTP server",2048,nntpserv,s,NULL,NULL,0);
  1992.     }
  1993.     return 0;
  1994. }
  1995.  
  1996. /* Shutdown NNTP service (existing connections are allowed to finish) */
  1997. int
  1998. nntp0(argc,argv,p)
  1999. int argc;
  2000. char *argv[];
  2001. void *p;
  2002. {
  2003.     return (deleteserver (&Snntp));
  2004. }
  2005.  
  2006. /* ---------------------------- Subcmds --------------------------- */
  2007.  
  2008. /* lists active newsgroups
  2009.  * returncode: -1 if error; 0 success */
  2010. static int
  2011. donnactive(argc,argv,p)
  2012. int argc;
  2013. char *argv[];
  2014. void *p;
  2015. {
  2016.     FILE *fp;
  2017.     char line[80], *cp;
  2018.  
  2019.     if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
  2020.         return -1;
  2021.  
  2022.     tputs("Msg#  next  mod newsgroup\n");
  2023.  
  2024.     for(;;) {
  2025.         if (fgets(line,sizeof(line),fp) == NULL)
  2026.             break;
  2027.         if((cp = strchr(line,' ')) == NULLCHAR)
  2028.             break;
  2029.         *cp = '\0';
  2030.         rip(++cp);
  2031.         tprintf("%s   %s\n",cp,line);
  2032.     }
  2033.     fclose(fp);
  2034.     return 0;
  2035. }
  2036.  
  2037. /* add nntp servers to list */
  2038. static int
  2039. donnadds(argc,argv,p)
  2040. int argc;
  2041. char *argv[];
  2042. void *p;
  2043. {
  2044.     struct Servers *np;
  2045.  
  2046.     for(np = Nntpserver; np != NULLSERVER; np = np->next)
  2047.         if(stricmp(np->name,argv[1]) == 0)
  2048.             break;
  2049.     if (np == NULLSERVER) {
  2050.         np = (struct Servers *)callocw(1,sizeof(struct Servers));
  2051.         if((np->dest = resolve(argv[1])) == 0) {
  2052.             tprintf(Badhost,argv[1]);
  2053.             free((char *)np);
  2054.             return -1;
  2055.         }
  2056.         np->name = strdup(argv[1]);
  2057.         np->next = Nntpserver;
  2058.         Nntpserver = np;
  2059.         np->newsgroups = NULLCHAR;
  2060.         np->lowtime = np->hightime = -1;
  2061.         np->nntpt.func = poll;        /* what to call on timeout */
  2062.         np->nntpt.arg = (void *)np;
  2063.     }
  2064.     if (argc > 3) {
  2065.         int i;
  2066.         if (np->newsgroups == NULLCHAR) {
  2067.             np->newsgroups = callocw(1,LineLen);
  2068.             *np->newsgroups = '\0';
  2069.         }
  2070.         for (i = 3; i < argc; ++i) {
  2071.             if (isdigit(*argv[i])) {
  2072.                 int lh, ll, hh, hl;
  2073.                 sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  2074.                 np->lowtime = lh * 100 + ll;
  2075.                 np->hightime = hh * 100 + hl;
  2076.             } else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
  2077.                 tprintf("To many groups, '%s' ignored\n", argv[i]);
  2078.             else {  /* it's a group, and it fits... add it to list */
  2079.                 if (*np->newsgroups != '\0')
  2080.                     strcat(np->newsgroups, ",");
  2081.                 strcat(np->newsgroups, argv[i]);
  2082.             }
  2083.         }
  2084.         if (*np->newsgroups == '\0') {    /* No groups specified? */
  2085.             free(np->newsgroups);
  2086.             np->newsgroups = NULLCHAR;
  2087.         }
  2088.     }
  2089.     /* set timer duration */
  2090.     set_timer(&np->nntpt,atol(argv[2])*1000L);
  2091.     start_timer(&np->nntpt);        /* and fire it up */
  2092.     return 0;
  2093. }
  2094.  
  2095. /* drops nntp servers from list */
  2096. static int
  2097. donndrops(argc,argv,p)
  2098. int argc;
  2099. char *argv[];
  2100. void *p;
  2101. {
  2102.     struct Servers *np, *npprev = NULLSERVER;
  2103.  
  2104.     for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
  2105.         if(stricmp(np->name,argv[1]) == 0) {
  2106.             stop_timer(&np->nntpt);
  2107.             free(np->name);
  2108.             if (np->newsgroups)
  2109.                 free(np->newsgroups);
  2110.             if(npprev != NULLSERVER)
  2111.                 npprev->next = np->next;
  2112.             else
  2113.                 Nntpserver = np->next;
  2114.             free((char *)np);
  2115.             return 0;
  2116.     }
  2117.     tputs("No such server enabled.\n");
  2118.     return -1;
  2119. }
  2120.  
  2121. /* copies a news from given newsgroup to the mailbox */
  2122. static int
  2123. donndump(argc,argv,p)
  2124. int argc;
  2125. char *argv[];
  2126. void *p;
  2127. {
  2128.     FILE *t, *f, *o;
  2129.     char path[LineLen], line[LineLen], *cp, newsname[25], *cp1;
  2130.     struct ffblk blk;
  2131.  
  2132.     if (!Filecheck)
  2133.         if(check_system())
  2134.             return -1;
  2135.  
  2136.     if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  2137.         return 0;
  2138.  
  2139.     path[0] = '\0';
  2140.     line[0] = '\0';
  2141.  
  2142.     for(;;) {
  2143.         if (fgets(line,LineLen,f) == NULL)
  2144.             break;
  2145.         if (!strncmp(line,argv[1],strlen(argv[1]))) {
  2146.             cp = strchr(line,' ') + 1;
  2147.             strcpy(path,cp);
  2148.             break;
  2149.         }
  2150.     }
  2151.     fclose(f);
  2152.  
  2153.     if (path[0] == '\0') {
  2154.         tprintf("No newsgroup %s\n",argv[1]);
  2155.         goto error;
  2156.     }
  2157.  
  2158.     rip2(path);
  2159.     cp = strrchr(path,'/');
  2160.     cp1 = &newsname[0];
  2161.  
  2162.     while(*cp)
  2163.         *(cp1++) = *(cp++);
  2164.     *cp1 = '\0';
  2165.  
  2166.     strcpy(line,path);
  2167.     strcat(line,"/*.*");
  2168.     if(findfirst(line,&blk,0)) {
  2169.         tputs("No news in newsgroup\n");
  2170.         goto error;
  2171.     }
  2172.     if(argc > 2)
  2173.         sprintf(newsname,"/%s",argv[2]);
  2174.  
  2175.     sprintf(line,"%s%s.txt",Mailspool,newsname);
  2176.     if ((o = open_file(line,"a+",0,1)) == NULLFILE)
  2177.         goto error;
  2178.     if(!(mlock(Mailspool,newsname))) {
  2179.         tprintf("Newsgroup dump to %s\n",line);
  2180.         for (;;) {
  2181.             if((t = temp_file(0,1)) == NULLFILE) {
  2182.                 fclose(o);
  2183.                 goto error;
  2184.             }
  2185.             sprintf(line,"%s/%s",path,blk.ff_name);
  2186.             /* Open the article */
  2187.             if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
  2188.                 fclose(t);
  2189.                 fclose(o);
  2190.                 goto error;
  2191.             }
  2192.             pwait(NULL);
  2193.             tputc('.'); /* One dot/article processed */
  2194.             tflush();
  2195.  
  2196.             for (;;) {
  2197.                 if (fgets(line,LineLen,f) == NULL)
  2198.                     break;
  2199.                 fputs(line,t);
  2200.                 if (!strnicmp(line,Hdrs[FROM],6)) {
  2201.                     cp = strchr(line,' ')+1;
  2202.                     fprintf(o,"From %s",cp);
  2203.                 }
  2204.             }
  2205.             rewind(t);
  2206.             for(;;) {
  2207.                 if (fgets(line,LineLen,t) == NULL)
  2208.                     break;
  2209.                 fputs(line,o);
  2210.             }
  2211.             fputc('\n',o);
  2212.             fclose(t);
  2213.             fclose(f);
  2214.             if (findnext(&blk))
  2215.                 break;
  2216.         }
  2217.         rmlock(Mailspool,newsname);
  2218.     } else
  2219.         tputs("Mailfile is busy, try later");
  2220.     fclose(o);
  2221.     tputs("\n");
  2222.  
  2223. error:
  2224.     return 0;
  2225. }
  2226.  
  2227. static int
  2228. donnkick(argc,argv,p)
  2229. int argc;
  2230. char *argv[];
  2231. void *p;
  2232. {
  2233.     struct Servers *np;
  2234.  
  2235.     for(np = Nntpserver; np != NULLSERVER; np = np->next)
  2236.         if(!stricmp(np->name,argv[1])) {
  2237.             /* If the timer is not running, the timeout function has
  2238.              * already been called and we don't want to call it again.
  2239.              */
  2240.             if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
  2241.                 stop_timer(&np->nntpt);
  2242.                 poll((void *)np);
  2243.             }
  2244.         return 0;
  2245.     }
  2246.     tputs("No server enabled\n");
  2247.     return 0;
  2248. }
  2249.  
  2250. /* list nntp servers */
  2251. static int
  2252. donnlists(argc,argv,p)
  2253. int argc;
  2254. char *argv[];
  2255. void *p;
  2256. {
  2257.     struct Servers *np;
  2258.     char tbuf[80];
  2259.  
  2260.     for(np = Nntpserver; np != NULLSERVER; np = np->next) {
  2261.         if (np->lowtime != -1 && np->hightime != -1)
  2262.             sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
  2263.                 np->lowtime/100, np->lowtime%100,
  2264.                 np->hightime/100, np->hightime%100);
  2265.         else
  2266.             tbuf[0] = '\0';
  2267.         tprintf("%-32s (%lu/%lu%s)\n   Groups: %s\n", np->name,
  2268.             read_timer(&np->nntpt) /1000L,
  2269.             dur_timer(&np->nntpt) /1000L,
  2270.             tbuf, np->newsgroups ? np->newsgroups : "");
  2271.     }
  2272.     return 0;
  2273. }
  2274.  
  2275. /* manually entering new news
  2276.  * returncode: -1 if error; 0 success */
  2277. static int
  2278. donnpost(argc,argv,p)
  2279. int argc;
  2280. char *argv[];
  2281. void *p;
  2282. {
  2283.     struct session *sp;
  2284.     struct nntpsv *mp;
  2285.     char buf[LineLen];
  2286.     int id;
  2287.     FILE *f, *idf, *ufp;
  2288.     long currtime;
  2289.  
  2290.     if (!Filecheck)
  2291.         if(check_system())
  2292.             return -1;
  2293.  
  2294.     if((sp = newsession("Post",0,1)) == NULLSESSION)
  2295.         return -1;
  2296.  
  2297.     mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  2298.  
  2299.     for (;;) {
  2300.         if ((f = temp_file(0,1)) == NULLFILE)
  2301.             goto done;
  2302.  
  2303.         sprintf(buf,"%s/sequence.seq",Mailqdir);
  2304.         if ((idf = open_file(buf,"r+",0,1)) == NULLFILE) {
  2305.             tprintf("Please create %s dir ...\n",Mailqdir);
  2306.             fclose(f);
  2307.             goto done;
  2308.         }
  2309.  
  2310.         id = atoi(fgets(buf,LineLen,idf));
  2311.         rewind(idf);
  2312.         fprintf(idf,"%d",id+2);
  2313.         fclose(idf);
  2314.  
  2315.         if (Post->user == NULLCHAR) {
  2316.             tputs("User name? ");
  2317.             recvline(sp->input,buf,LineLen);
  2318.             rip2(buf);
  2319.             Post->user = strdup(buf);
  2320.         }
  2321.         fprintf(f,"%s%s\n",Hdrs[PATH],Post->user);
  2322.         fprintf(f,"%s%s@%s",Hdrs[FROM],Post->user,Hostname);
  2323.         if (Post->fullname != NULLCHAR)
  2324.             fprintf(f," (%s )",Post->fullname);
  2325.         fputc('\n',f);
  2326.  
  2327.         tputs("Newsgroup? ");
  2328.         recvline(sp->input,buf,LineLen);
  2329.         rip2(buf);
  2330.         if (check_blank(buf))
  2331.             goto done;
  2332.         fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],buf);
  2333.  
  2334.         tputs("Subject? ");
  2335.         recvline(sp->input,buf,LineLen);
  2336.         fprintf(f,"%s%s",Hdrs[SUBJECT],buf);
  2337.         fprintf(f,"%s<%d@%s>\n",Hdrs[MSGID],id,Hostname);
  2338.         time(&currtime);
  2339.         fprintf(f,"Date: %s",ptime(&currtime));
  2340.         fprintf(f,"Sender: NNTP@%s\n",Hostname);
  2341.  
  2342.         if (Post->reply != NULLCHAR)
  2343.             fprintf(f,"%s%s\n",Hdrs[REPLYTO],Post->reply);
  2344.  
  2345.         if (Post->organ != NULLCHAR)
  2346.             fprintf(f,"Organization: %s\n",Post->organ);
  2347.  
  2348.         fputc('\n',f);
  2349.         tputs("Enter message - end with .\n");
  2350.  
  2351.         for (;;) {
  2352.             recvline(sp->input,buf,LineLen);
  2353.             if(strcmp(buf,".u\n") == 0
  2354.               || strcmp(buf,".r\n") == 0) {
  2355.                 tputs("Filename? ");
  2356.                 recvline(sp->input,buf,LineLen);
  2357.                 rip2(buf);
  2358.                 if((ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
  2359.                     while(fgets(buf,LineLen,ufp) != NULL)
  2360.                         fputs(buf,f);
  2361.                     fclose(ufp);
  2362.                 }
  2363.                 tputs("(continue)\n");
  2364.             }
  2365.             if(strcmp(buf,".\n") == 0
  2366.               || strcmpi(buf,"***END\n") == 0
  2367.               || strcmpi(buf,"/EX\n") == 0)
  2368.                 break;
  2369.             fputs(buf,f);
  2370.         }
  2371.  
  2372.         if (Post->sig != NULLCHAR) {
  2373.             sprintf(buf,"%s",Post->sig);
  2374.             if ((idf = open_file(buf,READ_TEXT,0,1)) != NULLFILE ) {
  2375.                 while(fgets(buf,LineLen,idf) != NULL)
  2376.                     fputs(buf,f);
  2377.                 fclose(idf);
  2378.             }
  2379.         }
  2380.  
  2381. loop:   tputs("\n[Send, Abort, Exit, List] ");
  2382.         recvline(sp->input,buf,LineLen);
  2383.         switch(tolower(buf[0])) {
  2384.         case 's':
  2385.             rewind(f);
  2386.             sprintf(mp->buf,"<%d@%s>",id,Hostname);
  2387.             mp->id = strdup(mp->buf);
  2388.             xfer_article2(f,mp);
  2389.             break;
  2390.         case 'l':
  2391.             rewind(f);
  2392.             for(;;) {
  2393.                 if (fgets(buf,LineLen,f) == NULL)
  2394.                     break;
  2395.                 tputs(buf);
  2396.             }
  2397.             rewind(f);
  2398.             goto loop;
  2399.         case 'e':
  2400.             fclose(f);
  2401.             goto done;
  2402.         case 'a':
  2403.             break;
  2404.         default:
  2405.             goto loop;
  2406.         }
  2407.         fclose(f);
  2408.         tputs("Post another? ");
  2409.         recvline(sp->input,buf,LineLen);
  2410.         if (tolower(buf[0]) == 'n')
  2411.             goto done;
  2412.     }
  2413.  
  2414. done:
  2415.     if(f != NULLFILE)
  2416.         fclose(f);
  2417.     keywait(NULLCHAR,1);
  2418.     free((char *) mp);
  2419.     freesession(sp);
  2420.     return 0;
  2421. }
  2422.  
  2423. static int
  2424. donnquiet(argc,argv,p)
  2425. int argc;
  2426. char *argv[];
  2427. void *p;
  2428. {
  2429.     return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,2);
  2430. }
  2431.  
  2432. /* -------------------- Profile subcmds -------------------- */
  2433.  
  2434. static int
  2435. donnuser(argc,argv,p)
  2436. int argc;
  2437. char *argv[];
  2438. void *p;
  2439. {
  2440.     if(argc < 2 && Post->user != NULLCHAR)
  2441.         tprintf("%s\n",Post->user);
  2442.     else {
  2443.         free(Post->user);
  2444.         Post->user = strdup(argv[1]);
  2445.     }
  2446.     return 0;
  2447. }
  2448.  
  2449. static int
  2450. donnsig(argc,argv,p)
  2451. int argc;
  2452. char *argv[];
  2453. void *p;
  2454. {
  2455.     if(argc < 2 && Post->sig != NULLCHAR)
  2456.         tprintf("%s\n",Post->sig);
  2457.     else {
  2458.         if(access(argv[1],0) == 0) {
  2459.             free(Post->sig);
  2460.             Post->sig = strdup(argv[1]);
  2461.         } else {
  2462.             tputs("No such signature file\n");
  2463.             return -1;
  2464.         }
  2465.     }
  2466.     return 0;
  2467. }
  2468.  
  2469. static int
  2470. donnfull(argc,argv,p)
  2471. int argc;
  2472. char *argv[];
  2473. void *p;
  2474. {
  2475.     if(argc < 2 && Post->fullname != NULLCHAR)
  2476.         tprintf("%s\n",Post->fullname);
  2477.     else {
  2478.         free(Post->fullname);
  2479.         Post->fullname = strdup(argv[1]);
  2480.     }
  2481.     return 0;
  2482. }
  2483.  
  2484. static int
  2485. donnhost(argc,argv,p)
  2486. int argc;
  2487. char *argv[];
  2488. void *p;
  2489. {
  2490.     if(argc < 2 && Host != NULLCHAR)
  2491.         tprintf("%s\n",Host);
  2492.     else {
  2493.         free(Host);
  2494.         Host = strdup(argv[1]);
  2495.     }
  2496.     return 0;
  2497. }
  2498.  
  2499. static int
  2500. donnorgan(argc,argv,p)
  2501. int argc;
  2502. char *argv[];
  2503. void *p;
  2504. {
  2505.     if(argc < 2 && Post->organ != NULLCHAR)
  2506.         tprintf("%s\n",Post->organ);
  2507.     else {
  2508.         free(Post->organ);
  2509.         Post->organ = strdup(argv[1]);
  2510.     }
  2511.     return 0;
  2512. }
  2513.  
  2514. static int
  2515. donnreply(argc,argv,p)
  2516. int argc;
  2517. char *argv[];
  2518. void *p;
  2519. {
  2520.     if(argc < 2 && Post->reply != NULLCHAR)
  2521.         tprintf("%s\n",Post->reply);
  2522.     else {
  2523.         free(Post->reply);
  2524.         Post->reply = strdup(argv[1]);
  2525.     }
  2526.     return 0;
  2527. }
  2528.  
  2529. static struct cmds Prof[] = {
  2530.         "fullname",    donnfull,    0, 0, NULLCHAR,
  2531.         "host",        donnhost,    0, 0, NULLCHAR,
  2532.         "organ",    donnorgan,    0, 0, NULLCHAR,
  2533.         "reply",    donnreply,    0, 0, NULLCHAR,
  2534.         "sig",        donnsig,     0, 0, NULLCHAR,
  2535.         "user",        donnuser,    0, 0, NULLCHAR,
  2536.         NULLCHAR,
  2537.     };
  2538.  
  2539. /* subcmd parser */
  2540. static int
  2541. donnprofile(argc,argv,p)
  2542. int argc;
  2543. char *argv[];
  2544. void *p;
  2545. {
  2546.     if(Post == NULLPOST) {
  2547.         Post = (struct post *)callocw(1,sizeof(struct post));
  2548.         Post->user = Post->reply = Post->sig = Post->organ = Post->fullname = NULLCHAR;
  2549.     }
  2550.     if (Host == NULLCHAR) {
  2551.         Host = strdup(Hostname);
  2552.     }
  2553.     return (argc == 10) ? 0 : (subcmd(Prof,argc,argv,p));
  2554. }
  2555.  
  2556. static struct cmds Nntp[] = {
  2557.         "active",    donnactive,        0,       0, NULLCHAR,
  2558.         "add",        donnadds,        0,       3, "nntp add <nntpserv> <interval> [<groups>]",
  2559.         "drop",        donndrops,        0,       2, "nntp drop <nntpserv>",
  2560.         "dump",     donndump,         0,       2, "nntp dump <newsgroup> [<mailbox>]",
  2561.         "kick",     donnkick,         0,       2, "nntp kick <server>",
  2562.         "list",        donnlists,        0,       0, NULLCHAR,
  2563.         "post",     donnpost,         2024, 0, NULLCHAR,
  2564.         "profile",    donnprofile,    0,       0, NULLCHAR,
  2565.         "quiet",    donnquiet,        0,      0, NULLCHAR,
  2566.         NULLCHAR,
  2567.     };
  2568.  
  2569. /* cmd parser */
  2570. int
  2571. donntp(argc,argv,p)
  2572. int argc;
  2573. char *argv[];
  2574. void *p;
  2575. {
  2576.     return (subcmd(Nntp,argc,argv,p));
  2577. }
  2578.  
  2579. /* main file-opening routine
  2580.  * options: s = socketnumber, if given an error msg is printed to the socket
  2581.  * returncode: NULLFILE if error; filepointer success
  2582.  */
  2583. FILE *
  2584. open_file(name,mode,s,t)
  2585. char *name;
  2586. char *mode;
  2587. int s;
  2588. int t;
  2589. {
  2590.     FILE *f;
  2591.     register char *cp;
  2592.  
  2593.     if(name == NULLCHAR || mode == NULLCHAR)
  2594.         return NULLFILE;
  2595. #ifdef MSDOS
  2596.     while((cp = strchr(name,'\\')) != NULLCHAR)
  2597.         *cp = '/';
  2598. #endif
  2599.     if((f = fopen(name,mode)) == NULLFILE) {
  2600.         if(s)
  2601.             usprintf(s,fatal,"",name);
  2602.         if(t)
  2603.             tprintf("Can't open %s: %s\n",name,sys_errlist[errno]);
  2604.     }
  2605.     return f;
  2606. }
  2607.  
  2608. /* main tempfile-opening routine
  2609.  * returncode: NULLFILE if error; filepointer success
  2610.  */
  2611. FILE *
  2612. temp_file(s,t)
  2613. int s;
  2614. int t;
  2615. {
  2616.     FILE *f;
  2617.  
  2618.     if((f = tmpfile()) == NULLFILE) {
  2619.         if(s)
  2620.             usprintf(s,fatal,"TMP","");
  2621.         if(t) {
  2622.             tprintf("Can't open TMP: %s\n",sys_errlist[errno]);
  2623.         }
  2624.     }
  2625.     return f;
  2626. }
  2627.  
  2628. /* Subroutine for setting and displaying int variables (with range check) */
  2629. int
  2630. setintrc(var, label, argc, argv, minval, maxval)
  2631. int16 *var;
  2632. char *label;
  2633. int argc;
  2634. char *argv[];
  2635. int minval;
  2636. int16 maxval;
  2637. {
  2638.     int tmp;
  2639.  
  2640.     if (argc < 2)
  2641.         tprintf("%s: %u\n", label, *var);
  2642.     else {
  2643.         tmp = atoi(argv[1]);
  2644.         if (isalpha(*argv[1]) || tmp < minval || tmp > maxval) {
  2645.             tprintf("%s must be %i..%i\n", label, minval, maxval);
  2646.             return 1;
  2647.         }
  2648.         *var = (int16)tmp;
  2649.     }
  2650.     return 0;
  2651. }
  2652. #endif /* NNTPS */
  2653.  
  2654.